package com.rbac.common.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.rbac.application.service.OperationLogService;
import com.rbac.application.service.UserService;
import com.rbac.common.annotation.OperationLog;
import com.rbac.domain.entity.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class OperationLogAspect {

    private final OperationLogService operationLogService;
    private final UserService userService;

    @Pointcut("@annotation(com.rbac.common.annotation.OperationLog)")
    public void operationLogPointcut() {}

    @Around("operationLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
        
        // 创建操作日志对象
        com.rbac.domain.entity.OperationLog operationLog = new com.rbac.domain.entity.OperationLog();
        
        try {
            // 获取当前用户信息
            if (StpUtil.isLogin()) {
                Long userId = StpUtil.getLoginIdAsLong();
                User user = userService.getById(userId);
                if (user != null) {
                    operationLog.setUserId(userId);
                    operationLog.setUsername(user.getUsername());
                }
            }
            
            // 获取注解信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            OperationLog annotation = method.getAnnotation(OperationLog.class);
            
            if (annotation != null) {
                operationLog.setOperation(StrUtil.isNotBlank(annotation.value()) ? annotation.value() : method.getName());
            }
            
            // 设置请求信息
            if (request != null) {
                operationLog.setMethod(request.getMethod() + " " + request.getRequestURI());
                operationLog.setIp(getClientIp(request));
                operationLog.setUserAgent(request.getHeader("User-Agent"));
                
                // 记录请求参数
                if (annotation != null && annotation.recordParams()) {
                    String params = getRequestParams(joinPoint, request);
                    operationLog.setParams(params);
                }
            }
            
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            // 记录成功信息
            operationLog.setStatus(1);
            if (annotation != null && annotation.recordResult()) {
                operationLog.setResult(JSONUtil.toJsonStr(result));
            }
            
            return result;
            
        } catch (Exception e) {
            // 记录异常信息
            operationLog.setStatus(0);
            operationLog.setErrorMsg(e.getMessage());
            throw e;
            
        } finally {
            // 计算执行时间
            long endTime = System.currentTimeMillis();
            operationLog.setExecutionTime(endTime - startTime);
            operationLog.setCreatedTime(LocalDateTime.now());
            
            // 异步保存日志
            try {
                operationLogService.saveLog(operationLog);
            } catch (Exception e) {
                log.error("保存操作日志失败: {}", e.getMessage(), e);
            }
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String xIp = request.getHeader("X-Real-IP");
        String xFor = request.getHeader("X-Forwarded-For");
        if (StrUtil.isNotBlank(xFor) && !"unknown".equalsIgnoreCase(xFor)) {
            int index = xFor.indexOf(",");
            if (index != -1) {
                return xFor.substring(0, index);
            } else {
                return xFor;
            }
        }
        if (StrUtil.isNotBlank(xIp) && !"unknown".equalsIgnoreCase(xIp)) {
            return xIp;
        }
        return request.getRemoteAddr();
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        try {
            // 获取方法参数
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0) {
                // 过滤敏感参数
                for (int i = 0; i < args.length; i++) {
                    if (args[i] instanceof HttpServletRequest || 
                        args[i] instanceof jakarta.servlet.http.HttpServletResponse) {
                        args[i] = null;
                    }
                }
                return JSONUtil.toJsonStr(args);
            }
            
            // 获取请求参数
            return JSONUtil.toJsonStr(request.getParameterMap());
        } catch (Exception e) {
            return "参数解析失败: " + e.getMessage();
        }
    }
}